from typing import List, Union, Tuple

from Voicelab.pipeline.Node import Node
from parselmouth.praat import call
from Voicelab.toolkits.Voicelab.VoicelabNode import VoicelabNode

###################################################################################################
# MANIPULATE PITCH NODE
# WARIO pipeline node for manipulating the pitch of a voice.
###################################################################################################
# ARGUMENTS
# 'voice'   : sound file generated by parselmouth praat
###################################################################################################
# RETURNS
###################################################################################################


class ManipulatePitchHigherNode(VoicelabNode):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.args = {
            "unit": ("ERB", ["ERB", "Hertz", "mel", "logHertz", "semitones"]),
            "method": ("Shift frequencies", ["Shift frequencies", "Multiply frequencies"]),
            "amount": 0.5,
            "time_step": 0.001,
            "normalize amplitude": True,
        }

    ###############################################################################################
    # process: WARIO hook called once for each voice file.
    ###############################################################################################

    def process(self):
        # initialize values
        sound = self.args["voice"]
        file_path = self.args["file_path"]
        unit = self.args["unit"][0]
        method: str = self.args["method"][0]
        if method == "Shift frequencies":
            amount = self.args["amount"]
        else:
            if self.args["amount"] > 1:
                amount = self.args["amount"] / 100
            else:
                amount = self.args["amount"]
        time_step = self.args["time_step"]
        f0min, f0max = self.pitch_bounds(sound)
        # create manipulation object
        manipulation = call(sound, "To Manipulation", time_step, f0min, f0max)
        # extract pitch tier
        pitch_tier = call(manipulation, "Extract pitch tier")
        # modify pitch tier and replace it
        call(pitch_tier, method, sound.xmin, sound.xmax, amount, unit)
        call([pitch_tier, manipulation], "Replace pitch tier")
        # resynthesize voices
        manipulated_sound = call(manipulation, "Get resynthesis (overlap-add)")
        if self.args["normalize amplitude"]:
            manipulated_sound.scale_intensity(70)

        output_file_name = file_path.split("/")[-1].split(".wav")[0]
        output_file_name = f"{output_file_name}_raise_pitch_{method}_{amount}_{unit}"

        manipulated_sound.name = output_file_name

        return {"voice": manipulated_sound}

